package com.company.loganalyzer.tools.impl;

import com.company.loganalyzer.dto.ToolInput;
import com.company.loganalyzer.dto.ToolResult;
import com.company.loganalyzer.dto.TraceAnalysisRequest;
import com.company.loganalyzer.dto.TraceAnalysisResponse;
import com.company.loganalyzer.tools.LogAnalysisTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * TraceId智能分析工具
 * 基于SkyWalking链路追踪，对指定traceId进行深度分析
 * 包括调用链分析、错误定位、根因分析和解决方案生成
 */
@Component
public class TraceAnalysisTool implements LogAnalysisTool {
    
    private static final Logger log = LoggerFactory.getLogger(TraceAnalysisTool.class);
    
    @Override
    public String getName() {
        return "trace_analysis";
    }
    
    @Override
    public String getDescription() {
        return "基于traceId进行智能链路分析，识别错误原因并提供解决方案";
    }
    
    @Override
    public ToolResult execute(ToolInput input) {
        log.info("执行TraceId智能分析: {}", input.getTraceId());
        
        try {
            // 1. 参数验证
            if (input.getTraceId() == null || input.getTraceId().trim().isEmpty()) {
                return ToolResult.error(getName(), "traceId参数不能为空");
            }
            
            // 2. 构建分析请求
            TraceAnalysisRequest request = buildAnalysisRequest(input);
            
            // 3. 执行链路分析
            TraceAnalysisResponse response = performTraceAnalysis(request);
            
            // 4. 返回分析结果
            return ToolResult.success(getName(), response);
            
        } catch (Exception e) {
            log.error("TraceId分析失败: {}", input.getTraceId(), e);
            return ToolResult.error(getName(), "分析失败: " + e.getMessage());
        }
    }
    
    /**
     * 构建分析请求
     */
    private TraceAnalysisRequest buildAnalysisRequest(ToolInput input) {
        TraceAnalysisRequest request = new TraceAnalysisRequest(input.getTraceId());
        
        // 设置时间范围
        if (input.getTimeRange() != null) {
            request.setTimeRange(input.getTimeRange());
        }
        
        // 设置服务名称
        if (input.getServiceName() != null) {
            request.setServiceName(input.getServiceName());
        }
        
        // 设置日志数量限制
        if (input.getLimit() != null) {
            request.setMaxLogs(input.getLimit());
        } else {
            request.setMaxLogs(1000); // 默认1000条
        }
        
        return request;
    }
    
    /**
     * 执行链路分析
     */
    private TraceAnalysisResponse performTraceAnalysis(TraceAnalysisRequest request) {
        String traceId = request.getTraceId();
        log.info("开始分析traceId: {}", traceId);
        
        // 创建响应对象
        TraceAnalysisResponse response = TraceAnalysisResponse.success(traceId);
        
        // 1. 模拟ES查询获取链路日志
        List<TraceAnalysisResponse.LogSnippet> traceLogs = fetchTraceLogsFromES(request);
        response.setRelatedLogs(traceLogs);
        
        // 2. 分析调用链路
        TraceAnalysisResponse.TraceChainAnalysis chainAnalysis = analyzeTraceChain(traceLogs);
        response.setChainAnalysis(chainAnalysis);
        
        // 3. 生成统计信息
        TraceAnalysisResponse.TraceStatistics statistics = generateStatistics(traceLogs);
        response.setStatistics(statistics);
        
        // 4. 生成问题分析
        generateProblemAnalysis(response, traceLogs, chainAnalysis, statistics);
        
        return response;
    }
    
    /**
     * 模拟从ES获取链路日志
     * 实际实现中这里会构建ES查询DSL
     */
    private List<TraceAnalysisResponse.LogSnippet> fetchTraceLogsFromES(TraceAnalysisRequest request) {
        String traceId = request.getTraceId();
        
        // 模拟返回一个完整的微服务调用链日志
        List<TraceAnalysisResponse.LogSnippet> logs = new ArrayList<>();
        
        // 模拟网关服务日志
        logs.add(new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.123",
            "INFO", 
            "api-gateway",
            "收到请求: POST /api/user/login, traceId=" + traceId
        ));
        
        // 模拟用户服务日志
        logs.add(new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.145",
            "INFO",
            "user-service", 
            "开始处理用户登录请求, userId=12345, traceId=" + traceId
        ));
        
        // 模拟数据库连接错误
        TraceAnalysisResponse.LogSnippet errorLog = new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.200",
            "ERROR",
            "user-service",
            "数据库连接失败: Connection timeout after 5000ms"
        );
        errorLog.setClassName("com.company.user.service.UserService");
        errorLog.setMethodName("validateUser");
        errorLog.setStackTrace("java.sql.SQLException: Connection timeout\n" +
                              "    at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:956)\n" +
                              "    at com.company.user.service.UserService.validateUser(UserService.java:45)\n" +
                              "    at com.company.user.controller.UserController.login(UserController.java:23)");
        logs.add(errorLog);
        
        // 模拟重试逻辑
        logs.add(new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.210",
            "WARN",
            "user-service",
            "重试数据库连接, 重试次数: 1/3, traceId=" + traceId
        ));
        
        // 模拟重试失败
        logs.add(new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.300",
            "ERROR", 
            "user-service",
            "数据库连接重试失败, 已达到最大重试次数, traceId=" + traceId
        ));
        
        // 模拟返回错误响应
        logs.add(new TraceAnalysisResponse.LogSnippet(
            "2025-01-09 14:30:01.305",
            "ERROR",
            "api-gateway", 
            "用户服务调用失败: 500 Internal Server Error, traceId=" + traceId
        ));
        
        return logs;
    }
    
    /**
     * 分析调用链路
     */
    private TraceAnalysisResponse.TraceChainAnalysis analyzeTraceChain(List<TraceAnalysisResponse.LogSnippet> logs) {
        TraceAnalysisResponse.TraceChainAnalysis analysis = new TraceAnalysisResponse.TraceChainAnalysis();
        
        // 提取服务调用链
        List<String> serviceChain = logs.stream()
            .map(TraceAnalysisResponse.LogSnippet::getServiceName)
            .distinct()
            .collect(Collectors.toList());
        analysis.setServiceChain(serviceChain);
        
        // 识别错误服务
        Optional<TraceAnalysisResponse.LogSnippet> firstError = logs.stream()
            .filter(log -> "ERROR".equals(log.getLevel()))
            .findFirst();
        
        if (firstError.isPresent()) {
            analysis.setErrorService(firstError.get().getServiceName());
            analysis.setErrorOperation(firstError.get().getMethodName());
            analysis.setRootCause("数据库连接超时导致用户认证失败");
        }
        
        // 计算总耗时（模拟）
        analysis.setTotalDuration(182L); // 模拟182ms
        
        // 各服务耗时分布
        Map<String, Long> serviceDurations = new HashMap<>();
        serviceDurations.put("api-gateway", 15L);
        serviceDurations.put("user-service", 167L);
        analysis.setServiceDurations(serviceDurations);
        
        return analysis;
    }
    
    /**
     * 生成统计信息
     */
    private TraceAnalysisResponse.TraceStatistics generateStatistics(List<TraceAnalysisResponse.LogSnippet> logs) {
        TraceAnalysisResponse.TraceStatistics stats = new TraceAnalysisResponse.TraceStatistics();
        
        stats.setTotalLogs(logs.size());
        stats.setErrorLogs((int) logs.stream().filter(log -> "ERROR".equals(log.getLevel())).count());
        stats.setWarnLogs((int) logs.stream().filter(log -> "WARN".equals(log.getLevel())).count());
        
        // 各服务日志数量统计
        Map<String, Integer> serviceLogCounts = logs.stream()
            .collect(Collectors.groupingBy(
                TraceAnalysisResponse.LogSnippet::getServiceName,
                Collectors.collectingAndThen(Collectors.counting(), Math::toIntExact)
            ));
        stats.setServiceLogCounts(serviceLogCounts);
        
        // 错误类型统计
        Map<String, Integer> errorTypes = new HashMap<>();
        errorTypes.put("数据库连接超时", 2);
        errorTypes.put("服务调用失败", 1);
        stats.setErrorTypes(errorTypes);
        
        return stats;
    }
    
    /**
     * 生成问题分析和解决方案
     */
    private void generateProblemAnalysis(TraceAnalysisResponse response, 
                                       List<TraceAnalysisResponse.LogSnippet> logs,
                                       TraceAnalysisResponse.TraceChainAnalysis chainAnalysis,
                                       TraceAnalysisResponse.TraceStatistics statistics) {
        
        // 1. 问题摘要
        String problemSummary = String.format(
            "TraceId %s 在用户认证流程中发生数据库连接超时错误。" +
            "错误发生在 %s 服务的 %s 操作，导致整个调用链失败。" +
            "总共产生 %d 条日志，其中 %d 条错误日志，%d 条警告日志。",
            response.getTraceId(),
            chainAnalysis.getErrorService(),
            chainAnalysis.getErrorOperation(),
            statistics.getTotalLogs(),
            statistics.getErrorLogs(),
            statistics.getWarnLogs()
        );
        response.setProblemSummary(problemSummary);
        
        // 2. 详细分析
        StringBuilder detailedAnalysis = new StringBuilder();
        detailedAnalysis.append("## 调用链路分析\n");
        detailedAnalysis.append("**服务调用路径**: ").append(String.join(" -> ", chainAnalysis.getServiceChain())).append("\n");
        detailedAnalysis.append("**总耗时**: ").append(chainAnalysis.getTotalDuration()).append("ms\n");
        detailedAnalysis.append("**错误服务**: ").append(chainAnalysis.getErrorService()).append("\n\n");
        
        detailedAnalysis.append("## 错误详情\n");
        detailedAnalysis.append("**根本原因**: ").append(chainAnalysis.getRootCause()).append("\n");
        detailedAnalysis.append("**首次错误时间**: 2025-01-09 14:30:01.200\n");
        detailedAnalysis.append("**错误类型**: 数据库连接超时 (Connection timeout after 5000ms)\n");
        detailedAnalysis.append("**影响范围**: 用户登录功能完全不可用\n\n");
        
        detailedAnalysis.append("## 服务行为分析\n");
        detailedAnalysis.append("1. **api-gateway**: 正常接收请求并转发到用户服务\n");
        detailedAnalysis.append("2. **user-service**: 尝试连接数据库验证用户凭据时超时\n");
        detailedAnalysis.append("3. **重试机制**: 触发了重试逻辑，但仍然失败\n");
        detailedAnalysis.append("4. **错误传播**: 错误正确地传播回网关并返回给客户端\n");
        
        response.setDetailedAnalysis(detailedAnalysis.toString());
        
        // 3. 解决步骤
        List<String> solutionSteps = Arrays.asList(
            "立即检查数据库服务状态和连接池配置",
            "检查网络连接状况，确认数据库服务器可达性",
            "审查数据库连接池设置：超时时间、最大连接数、空闲连接数",
            "检查数据库服务器资源使用情况（CPU、内存、磁盘I/O）",
            "查看数据库慢查询日志，排查是否有阻塞查询",
            "考虑增加数据库连接超时时间（当前5秒可能过短）",
            "优化重试策略：增加指数退避机制",
            "添加数据库连接监控和告警",
            "考虑实施熔断器模式防止级联失败",
            "建立数据库故障时的降级策略（如缓存认证信息）"
        );
        response.setSolutionSteps(solutionSteps);
        
        // 4. 设置元数据
        Map<String, Object> metadata = new HashMap<>();
        metadata.put("analysisType", "trace_chain_analysis");
        metadata.put("skyWalkingCompatible", true);
        metadata.put("errorCategory", "database_connectivity");
        metadata.put("severity", "high");
        metadata.put("affectedServices", chainAnalysis.getServiceChain());
        response.setMetadata(metadata);
    }
}